#pragma once

#include <vector>
#include <string>
#include <cstdint>
#include <cassert>
#include <cstring>

#define BUFFER_DEFAULT_SIZE 1024
class Buffer
{
private:
    char* Begin()
    {
        return &_buffer[0];
    }

    const char* Begin() const
    {
        return &*_buffer.begin();
    }
public:
    Buffer()
     : _reader_idx(0)
     , _writer_idx(0)
     , _buffer(BUFFER_DEFAULT_SIZE)
    {}
    // 获取当前读取起始地址
    char* GetReadAddr()
    {
        return Begin() + _reader_idx;
    }

    const char* GetReadAddr() const
    {
        return Begin() + _reader_idx;
    }

    // 获取当前写入起始地址
    char* GetWriteAddr()
    {
        return Begin() + _writer_idx;
    }

    const char* GetWriteAddr() const
    {
        return Begin() + _writer_idx;
    }

    // 获取缓冲区起始空间大小---读偏移之前的空闲空间
    uint64_t GetHeadIdleSize() const
    {
        return _reader_idx;
    }

    // 获取缓冲区末尾空间大小---写偏移之后的空闲空间
    uint64_t GetTailIdleSize() const
    {
        return _buffer.size() - _writer_idx;
    }

    // 获取可读大小
    uint64_t GetReadableSize() const
    {
        return _writer_idx - _reader_idx;
    }

    // 获取可写大小
    uint64_t GetWritableSize() const
    {
        return GetHeadIdleSize() + GetTailIdleSize();
    }

    // 将读偏移向后移动
    void MoveBackReadOffset(uint64_t len)
    {
        if (len == 0)   return;
        assert(len <= GetReadableSize());
        _reader_idx += len;
    }

    // 将写偏移向后移动
    void MoveBackWriteOffset(uint64_t len)
    {
        assert(len <= GetTailIdleSize());
        _writer_idx += len;
    }

    // 确保可写空间足够（整体空闲空间够了就移动数据，否则就扩容）
    void CheckWriteIdle(uint64_t len)
    {
        if (len <= GetTailIdleSize())   return; // 缓冲区末尾空间大小足够
        if (len <= GetWritableSize()) // 可写空间大小足够
        {
            uint64_t readsize = GetReadableSize();
            std::copy(GetReadAddr(), GetReadAddr() + readsize, Begin());
            _reader_idx = 0;
            _writer_idx = readsize;
        }
        else
            _buffer.resize(std::max(_buffer.size() * 2, _writer_idx + len));
    }

    // 读取数据
    void Read(void* const buf, uint64_t len)
    {
        assert(len <= GetReadableSize());
        std::copy(GetReadAddr(), GetReadAddr() + len, (char*)buf);
        MoveBackReadOffset(len);
    }

    // 输出型参数
    void Read(std::string* const buf, uint64_t len)
    {
        assert(len <= GetReadableSize());
        (*buf).resize(len);
        std::copy(GetReadAddr(), GetReadAddr() + len, &(*buf)[0]); // 直接复制
        MoveBackReadOffset(len);
    }

    // 写入数据
    void Write(const void* const data, uint64_t len) // C风格的data
    {
        if (len == 0) return;
        CheckWriteIdle(len);
        char* tmp = (char*)data;
        std::copy(tmp, tmp + len, GetWriteAddr());
        MoveBackWriteOffset(len);
    }
    
    // 输入型参数
    void Write(const std::string& data) // C++风格的字符串
    {
        Write(data.c_str(), data.length());
    }

    // 输入型参数
    void Write(const Buffer& data)
    {
        Write(data.GetReadAddr(), data.GetReadableSize());
    }

    // 清空缓冲区
    void Clear()
    {
        _reader_idx = _writer_idx = 0;
    }

    char* FindCRLF() // 寻找回车换行
    {
        char* ret = (char*)memchr(GetReadAddr(), '\n', GetReadableSize());
        return ret;
    }

    std::string GetLine()
    {
        char* pos = FindCRLF();
        if (pos == nullptr) return "";
        std::string buf;
        Read(&buf, pos - GetReadAddr() + 1); // 这块选择把换行符也提取出来
        return std::move(buf); // 这块是支持http的字符串行读取，移动构造返回，加快效率
    }

    ~Buffer() {}
private:
    std::vector<char> _buffer;
    uint64_t _reader_idx; // 读偏移
    uint64_t _writer_idx; // 写偏移
};